module LPM

  # you could use utils like this:
  # LPM::Utils.cpu(5)
  # => {"cpu"=>100.0, "cpu0"=>100.0, "cpu1"=>100.0}

  # also could use Utils as below:
  # LPM::Proc.cpu(5)
  # => {"cpu"=>100.0, "cpu0"=>100.0, "cpu1"=>100.0}
  module Utils
    module Proc
      def pids(*arguments)
        Dir.chdir '/proc'
        Dir['[0-9]*'].inject([]) { |r, p|
          r << {:pid => p, :cmdline => IO.read("#{p}/cmdline").gsub(/\000/,' ')}
        }
      end
      
      def date(*arguments)
        `date +"%F %T"`.chomp
      end

      def df(*arguments)
        size,use,avai = 0,0,0
        str = `df`
        arr = str.split($/)
        arr.shift
        arr.each { |l| x = l.split; size += x[1].to_i; use += x[2].to_i; avai += x[3].to_i  }
        {:size => size,:use => use,:avai => avai}
      end
      
      # ulimit -n is the most useful.
      # it limitted the count of total available socket.
      def ulimit(*arguments)
        `ulimit -a`.split($/).map do |line|
          a,b = line.split(/\s*\(.*?\)\s*/)
          {a=>b}
        end
      end

      # attention: sysctl seperator is ':' in macos.
      def sysctl(*arguments)
        `sysctl -a`.split($/).map do |line|
          a,b = line.split(/\s*=\s*/)
          {a=>b}
        end
      end

      def locale(*arguments)
        `locale`.split($/).map do |line|
          a,b = line.split(/\s*=\s*/)
          {a=>b}
        end
      end

      # get cpu useage.
      # total_0=USER[0]+NICE[0]+SYSTEM[0]+IDLE[0]+IOWAIT[0]+IRQ[0]+SOFTIRQ[0]
      # sleep x
      # total_1=USER[1]+NICE[1]+SYSTEM[1]+IDLE[1]+IOWAIT[1]+IRQ[1]+SOFTIRQ[1]
      # cpu_usage=(IDLE[0]-IDLE[1]) / (total_0-total_1) * 100

      # scale is 100
      # cpu(5) => {"cpu3"=>99.3333333333333, "cpu"=>99.75, "cpu0"=>100.0, "cpu1"=>100.0, "cpu2"=>99.3355481727575}

      def cpu(interv=3,debug=false,*arguments)
        begin
          interv = interv.to_i
        rescue NoMethodError => e
          interv = 3
        end
        
        def getCpuStat(debug=false)
          h = {}
          IO.read('/proc/stat').split($/).map do|line|
            a = line.split
            # p "line => #{a.inspect}" if debug
            #     user    nice system idle      iowait  irq  softirq
            #cpu  1961269 660 285319 1290544224 1522385 2383 0
            if(a[0]=~/cpu/)
              # raise CpuLineSizeError,"The count of words each line is not equal 8." if a.size != 8
              # p "cpu line => #{a.inspect}" if debug
              h[a[0]] = {:total => a[1..-1].inject(0) do |sum,i|
                                                        sum += i.to_f
                                                      end,
                          :idle => a[4].to_f}
              # p "idle => #{h[a[0]][:idle]}" if debug
            end
          end
          h
        end

        def getCpuUseage(h1,h2,debug=false)
          # p h1.inspect if debug
          # p h2.inspect if debug
          # p "h2[:idle]-h1[:idle] = #{(h2[:idle]-h1[:idle]).to_f}" if debug
          # p "h2[:total]-h1[:total] = #{(h2[:total]-h1[:total]).to_f}" if debug
          100 - (h2[:idle]-h1[:idle]).to_f/(h2[:total]-h1[:total]).to_f * 100
        end

        cpu_old,cpu_new = {},{}
        
        th = Thread.fork do
          cpu_old = getCpuStat(debug)
          sleep interv
          cpu_new = getCpuStat(debug)
        end

        th.join
        
        r = {}
        cpu_old.each do |k,v|
          r[k.to_sym] =getCpuUseage(cpu_old[k],cpu_new[k],debug)
        end
        r
      end
      
      def hostname(*arguments)
        `hostname`.chomp
      end
    end

    # LPM::Process included the Process module,
    # you can use as:
    # => LPM::Process.new(pid).cpu
    # then you will get that pid process's cpu total useage.
    module Process

      # rate = ((utime2+stime2) - (utime1+stime1)) / (total2 - total1)
      # total = user + sys + idle + nice or get value from /proc/uptime
      def cpu(interv=3,*arguments)
        utime1,stime1,starttime1,total1,idle1 = nil
        utime2,stime2,starttime2,total2,idle2 = nil

        # t = Thread.fork do
        utime1,stime1,starttime1 = IO.read("#{@pwd}/stat").split.values_at(15,16,23).map{|x|x.to_f}
        # Attention : uptime file's end contain $/
        # "3394903.84 3389669.77\n"
        # if run in Thread,
        # Process will hang on IO.read('/proc/uptime')
        # like this => http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/125125
        # i don't know why.
        total1,idle1 = IO.read('/proc/uptime').chop.split.map{|x|x.to_f}
        sleep interv
        utime2,stime2,starttime2 = IO.read("#{@pwd}/stat").split.values_at(15,16,23).map{|x|x.to_f}
        total2,idle2 = IO.read('/proc/uptime').chop.split.map{|x|x.to_f}
        # end
        
        # t.join
        ((utime2+stime2) - (utime1+stime1)).to_f / (total2 - total1).to_f
      end
      
      def mem(*arguments)
        (IO.read("#{@pwd}/statm").split.shift.to_f/1024).to_s
      end
    end
    
    class << self;include Proc;end
  end

  # insert into LPM::Proc's meta class.
  begin
    (class << LPM::Proc;include Utils::Proc;end) unless LPM::Proc.include? Utils::Proc
    LPM::Process.send :include,Utils::Process
  rescue NameError
    require File.join(File.dirname(__FILE__),'proc.rb')
    require File.join(File.dirname(__FILE__),'process.rb')
    retry
  end

end